package com.wssnail.redis.lock;

import com.wssnail.redis.key.BaseKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;

import java.util.Collections;

/**
*@Author: yan
*@CreateTime:2022/7/14 9:37
*@Description: redis分布式锁,该锁不支持锁重入，如需要重入请使用redission或自行修改
*@Version: 1.0
*/
@Slf4j
public class RedisTemplateDistributeLock implements DistributeLock{

    private BaseKey baseKey;

    public RedisTemplateDistributeLock(BaseKey baseKey){
        this.baseKey=baseKey;
    }
 
    private static final Long SUCCESS = 1L;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public boolean tryLock(String lockKey, String value, Long expireTime) {
        try {
            //lua脚本
            String finalKey = String.format(baseKey.getPrefix() + "%s", lockKey);
            String script = "if redis.call('setNx',KEYS[1],ARGV[1]) == 1 then if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end else return 0 end";
            Long result = (Long) redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList(finalKey), value, expireTime);
            return SUCCESS.equals(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /*
     * @description:释放锁
     * @author: yan
     * @date: 2022/7/14 9:41
     * @param lockKey
     * @param value
     * @return:
     * @return: boolean
     **/
    @Override
    public boolean releaseLock(String lockKey, String value) {
        try {
            String finalKey = String.format(baseKey.getPrefix() + "%s", lockKey);
            //lua脚本
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
            Long result = (Long) redisTemplate.execute(redisScript, Collections.singletonList(finalKey), value);
            return SUCCESS.equals(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

}